package com.mar.bt.server.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.bluetooth.RemoteDevice;

import net.java.dev.marge.communication.CommunicationListener;
import net.java.dev.marge.communication.ConnectionListener;
import net.java.dev.marge.entity.ServerDevice;
import net.java.dev.marge.entity.config.ServerConfiguration;
import net.java.dev.marge.factory.CommunicationFactory;

import com.mar.bt.server.IBTClientsListener;
import com.mar.bt.server.IBluetoothIOHandler;
import com.mar.bt.server.IBluetoothServer;

/**
 * Base implementation of {@link IBluetoothServer}.<br/>
 * Extension methods:
 * <ul>
 * <li><b>createServerConfiguration</b> - to create and configure {@link ServerConfiguration} object</li>
 * <li><b>createCommunicationFactory</b> - to create a {@link CommunicationFactory}
 * (that represents communication protocol) object. </li>
 * <li><b>createBTIOHandler</b> - to create BT input/output handler for an opened connection</li>
 * </ul>
 * 
 * @author mar
 *
 */
public abstract class BluetoothServer implements IBluetoothServer {

	private List<IBluetoothIOHandler> openedConnections = new ArrayList<IBluetoothIOHandler>();
	
	private final CommunicationFactory communicationFactory;
	private final ServerConfiguration serverConfig;
	
	
	public BluetoothServer() {		
		this.communicationFactory = createCommunicationFactory();
        this.serverConfig = createServerConfiguration();
    }
	
	/**
	 * Default creates configuration and sets maximum number of connection to 2.
	 * @return
	 */
	protected ServerConfiguration createServerConfiguration(){
//        TODO: this is actual for l2cap protocol
//        Hashtable< String , String> table = new Hashtable<String, String>();
//        table.put("ReceiveMTU","1024");
//        table.put("TransmitMTU","1024");
//        config.setParameters(table);
		
		ServerConfiguration serverConfiguration = new ServerConfiguration(new InternalCommunicationListener() );
		serverConfiguration.setMaxNumberOfConnections(2);
		return serverConfiguration;
	}
	
	protected abstract CommunicationFactory createCommunicationFactory();
	
	/* (non-Javadoc)
	 * @see com.mar.bt.server.IBluetoothHandler#startListening(com.mar.bt.server.BTClientsListener)
	 */
	public void startListening(IBTClientsListener clientListener){
		this.communicationFactory.waitClients(serverConfig, new InternalConnectionListener(clientListener));	
	}
	
	/* (non-Javadoc)
	 * @see com.mar.bt.server.IBluetoothHandler#shutdown()
	 */
	public void shutdown(){
		synchronized (openedConnections) {
			for ( IBluetoothIOHandler btIoHandler : openedConnections ){
				btIoHandler.close();
			}
		}
	}
	
	private class InternalCommunicationListener implements CommunicationListener{

		public void errorOnReceiving(IOException arg0) {
			arg0.printStackTrace();
		}

		public void errorOnSending(IOException arg0) {
			arg0.printStackTrace();			
		}

		public void receiveMessage(byte[] arg0) {
			
		}
		
	}
	
	protected class InternalConnectionListener implements ConnectionListener{
		private final IBTClientsListener clientsListener;
		
		public InternalConnectionListener(IBTClientsListener clientsListener) {
			this.clientsListener = clientsListener;
		}

		public void connectionEstablished(ServerDevice server, RemoteDevice client) {
			IBluetoothIOHandler btIOHandler = createBTIOHandler(server);
			registerConnection(btIOHandler);
			clientsListener.clientConnected(client, btIOHandler);
		}

		public void errorOnConnection(IOException arg0) {
			arg0.printStackTrace();
		}
		
	}
	

	/**
	 * Internal factory method for instantiating new bluetooth io handler
	 * @param serviceDevice
	 * @return
	 */
	protected abstract IBluetoothIOHandler createBTIOHandler(ServerDevice serviceDevice);
	
	protected final void registerConnection(IBluetoothIOHandler handler){
		synchronized (openedConnections) {
			openedConnections.add(handler);
		}
	}
	
}
